//The MIT License
//
//Copyright (c) 2009 nodchip
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in
//all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
//THE SOFTWARE.
package tv.dyndns.kishibe.server;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;

import tv.dyndns.kishibe.client.Constant;
import tv.dyndns.kishibe.client.Controller;
import tv.dyndns.kishibe.client.game.WidgetInputTyping;
import tv.dyndns.kishibe.client.geom.Point;
import tv.dyndns.kishibe.client.geom.Polygon;
import tv.dyndns.kishibe.client.packet.PacketProblemData;

//これってデコレータパターンじゃね？
public class ComputerPlayer {
	private static final double MAX_COM_STRENGTH = 0.5;
	private final Random random = new Random();
	private double comStrength = 0.5;
	private static final String COM_NAME[] = { "レオン", "ルッツ", "ユルグ", "マサヒロサマ", "セリオス", "マテウス", "レクトール", "デスマテウス", "VJGYO", "カイル", "マルコ", "アーベル", "メガネはる", "HIDEKI", "ラスク", "ジーク", "ガブリエル", "まっはー", "クララ", "ファニー", "ナタリー", "トモちゃん", "ドクターコハ", "ルキア", "ディアナ", "ヒルダ", "シャロン", "トゥエット", "レイア", "アロエ", "ミルス", "マリー", "ちよちゃん", "MARS", "サンダース", "ハートマン", "ウィーグル", "アフロ", "マラリヤ", "アザリン", "イザベラ", "タイガ", "ドラゴン", "カープ", "ダニエル", "エイリやん", "ユリ", "ナツミ", "サラ", "かれいなほし", "ユウ&サツキ", "イオリ", "チヒロ", "ヤンヤン", "ユンユン", "ヨンヨン" };
	private static final String GREETING[] = {
	// 以下ぷよぷよシリーズより
			"行っきまーす", "おちゃー", "はらほろひれはれー♪", "ひゃっほう ぬはー!", "負っけないからねぇ!", "彼女～v", "ふぃーっしゅ!", "お掃除しちゃうぞ☆", "のっほっほー", "じゃいやー!", "おいッス", "魔王だぞぅ", "近う寄れ", "勇者に敗北はない!", "かかってらっしゃい!", "行くぜ!", "抵抗する気か", "きゃはっ", "やっほぉー", "ピチピチよ!", "がぉー", "戦うのですか？", "ふふっ", "毎度ー", "ウゥモォー！", "ぐーーっ！" };
	private final PlayerAnswer playerAnswer;

	public ComputerPlayer(List<Integer> problemIDs) {
		playerAnswer = new PlayerAnswer(problemIDs);
	}

	public String getName(int classLevel) {
		if (classLevel == Constant.MAX_CLASS_LEVEL) {
			if (random.nextBoolean()) {
				return "(COM) マテウス";
			} else {
				return "(COM) デスマテウス";
			}
		}

		return "(COM) " + COM_NAME[random.nextInt(COM_NAME.length)];
	}

	public String getAnswer(PacketProblemData problem, String name, int classLevel) {
		if (classLevel == Constant.CLASS_LEVEL_NORMAL) {
			classLevel = 10;
		}
		classLevel = Math.min(Constant.NUMBER_OF_CLASSES - 2, Math.max(2, classLevel));

		comStrength = Math.min(MAX_COM_STRENGTH, (double) classLevel / (double) Constant.NUMBER_OF_CLASSES);
		// if (name.contains("デスマテウス")) {
		// comStrength = 1.0;
		// } else if (name.contains("マテウス")) {
		// comStrength = 0.9;
		// }

		switch (problem.type) {
		case Constant.TYPE_MARUBATU:
			return getAnswerMaruBatu(problem);
		case Constant.TYPE_4TAKU:
		case Constant.TYPE_RENSOU:
			return getAnswerChoice(problem);
		case Constant.TYPE_NARABEKAE:
		case Constant.TYPE_FLASH:
			return getAnswerNarabekae(problem);
		case Constant.TYPE_MOJIPANEL:
			return getAnswerMojiPanel(problem);
		case Constant.TYPE_TYPING:
		case Constant.TYPE_EFFECT:
			return getAnswerTyping(problem);
		case Constant.TYPE_TATO:
			return getAnswerTato(problem);
		case Constant.TYPE_JUNBAN:
			return getAnswerJunban(problem);
		case Constant.TYPE_SENMUSUBI:
			return getAnswerSenmusubi(problem);
		case Constant.TYPE_SLOT:
			return getAnswerSlot(problem);
		case Constant.TYPE_CLICK:
			return getAnswerClick(problem);
		case Constant.TYPE_TEGAKI:
			return getAnswerTegaki(problem);
		default:
			break;
		}

		return "・・・・・・・・";
	}

	private boolean correct() {
		return random.nextDouble() < comStrength;
	}

	private String joke(int problemID) {
		if (random.nextBoolean()) {
			return null;
		}

		return playerAnswer.get(problemID);
	}

	static private final String MARU_BATU[] = { "○", "×" };

	private String getAnswerMaruBatu(PacketProblemData problem) {
		if (correct()) {
			return problem.answer[0];
		}

		if (problem.imageChoice) {
			return problem.choice[random.nextInt(2)];
		}

		return MARU_BATU[random.nextInt(2)];
	}

	private String getAnswerChoice(PacketProblemData problem) {
		try {
			if (correct()) {
				return problem.answer[0];
			}
		} catch (Exception e) {
			return "・・・・・・・・";
		}

		return problem.choice[random.nextInt(4)];
	}

	private String randomShuffle(String s) {
		List<String> list = new ArrayList<String>();
		for (int i = 0; i < s.length(); ++i) {
			list.add(s.substring(i, i + 1));
		}
		Collections.shuffle(list);

		String res = "";
		for (int i = 0; i < list.size(); ++i) {
			res += (String) list.get(i);
		}

		return res;
	}

	private String getAnswerNarabekae(PacketProblemData problem) {
		if (correct()) {
			return problem.answer[0];
		}

		String answer = joke(problem.problemId);
		if (answer != null) {
			return answer;
		}

		return randomShuffle(problem.answer[0]);
	}

	private String getAnswerMojiPanel(PacketProblemData problem) {
		if (correct()) {
			return problem.answer[0];
		}

		String answer = joke(problem.problemId);
		if (answer != null) {
			return answer;
		}

		return randomShuffle(problem.choice[0]).substring(0, 4);
	}

	private static final String LETTERS[] = { "あかさたなはまやらわいきしちにひみりをうくすつぬふむゆるんえけせてねへめれおこそとのほもよろー", "アカサタナハマヤラワイキシチニヒミリヲウクスツヌフムユルンエケセテネヘメレオコソトノホモヨロー", "０１２３４５６７８９ＡＢＣＤＥＦＧＨＩＪＫＬＭＮＯＰＱＲＳＴＵＶＷＸＹＺ" };

	private String getAnswerTyping(PacketProblemData problem) {
		if (correct()) {
			int numberOfAnswer = problem.getNumberOfAnswer();
			return problem.answer[random.nextInt(numberOfAnswer)];
		}

		String answer = joke(problem.problemId);
		if (answer != null) {
			return answer;
		}

		int type;
		char ch = problem.answer[0].charAt(0);
		if (0x3041 <= ch && ch <= 0x309e) {
			type = WidgetInputTyping.TYPING_HIRA;
		} else if (0x30a1 <= ch && ch <= 0x30f6) {
			type = WidgetInputTyping.TYPING_KATA;
		} else if ('Ａ' <= ch && ch <= 'Ｚ' || '０' <= ch && ch <= '９') {
			type = WidgetInputTyping.TYPING_ALPHA;
		} else {
			type = 0;
			Controller.getInstance().showErrorMessage("タイピング入力ウィジットに問題発生");
		}

		answer = "";
		int answerIndex = 0;
		for (int i = 0; i < problem.answer[answerIndex].length(); ++i) {
			int index = random.nextInt(LETTERS[type].length());
			answer += LETTERS[type].substring(index, index + 1);
		}

		return answer;
	}

	private String getAnswerTato(PacketProblemData problem) {
		final int numberOfAnswer = problem.getNumberOfAnswer();
		String answer = "";
		if (correct()) {
			for (int i = 0; i < numberOfAnswer; ++i) {
				if (answer.length() != 0) {
					answer += "\n";
				}
				answer += problem.answer[i];
			}
			return answer;
		}

		answer = "";
		for (int i = 0; i < numberOfAnswer; ++i) {
			if (random.nextBoolean()) {
				if (answer.length() != 0) {
					answer += Constant.DELIMITER_GENERAL;
				}
				answer += problem.choice[i];
			}
		}
		return answer;

	}

	private String getAnswerJunban(PacketProblemData problem) {
		final int numberOfAnswer = problem.getNumberOfAnswer();
		String answer = "";
		if (correct()) {
			for (int i = 0; i < numberOfAnswer; ++i) {
				if (answer.length() != 0) {
					answer += Constant.DELIMITER_GENERAL;
				}
				answer += problem.answer[i];
			}
			return answer;
		}

		int perm[] = Utility.getInstance().makePermutationArray(numberOfAnswer);

		for (int i = 0; i < numberOfAnswer; ++i) {
			if (answer.length() != 0) {
				answer += "\n";
			}
			answer += problem.answer[perm[i]];
		}
		return answer;

	}

	private String getAnswerSenmusubi(PacketProblemData problem) {
		final int numberOfAnswer = problem.getNumberOfAnswer();
		String answer = "";
		int perm[] = Utility.getInstance().makePermutationArray(numberOfAnswer);
		if (correct()) {
			for (int i = 0; i < numberOfAnswer; ++i) {
				if (i != 0) {
					answer += Constant.DELIMITER_GENERAL;
				}
				answer += problem.choice[perm[i]];
				answer += Constant.DELIMITER_KUMIAWASE_PAIR;
				answer += problem.answer[perm[i]];
			}

			return answer;
		}

		int perm2[] = Utility.getInstance().makePermutationArray(numberOfAnswer);
		for (int i = 0; i < numberOfAnswer; ++i) {
			if (i != 0) {
				answer += Constant.DELIMITER_GENERAL;
			}
			answer += problem.choice[perm[i]];
			answer += Constant.DELIMITER_KUMIAWASE_PAIR;
			answer += problem.answer[perm2[i]];
		}
		return answer;

	}

	private String getAnswerSlot(PacketProblemData problem) {
		if (correct()) {
			return problem.answer[0];
		}

		String answer = joke(problem.problemId);
		if (answer != null) {
			return answer;
		}

		final StringBuilder b = new StringBuilder();
		int length = problem.answer[0].length();
		final int numberOfAnswer = problem.getNumberOfAnswer();
		for (int x = 0; x < length; ++x) {
			b.append(problem.answer[random.nextInt(numberOfAnswer)].substring(x, x + 1));
		}

		return b.toString();
	}

	private String getAnswerClick(PacketProblemData problem) {
		if (correct()) {
			// 領域の最大最小を求める
			int minX = Integer.MAX_VALUE;
			int minY = Integer.MAX_VALUE;
			int maxX = Integer.MIN_VALUE;
			int maxY = Integer.MIN_VALUE;
			final int answerIndex = random.nextInt(problem.getNumberOfAnswer());
			final Polygon polygon = new Polygon(problem.answer[answerIndex]);
			for (Point point : polygon) {
				minX = Math.min(minX, point.x);
				minY = Math.min(minY, point.y);
				maxX = Math.max(maxX, point.x);
				maxY = Math.max(maxY, point.y);
			}

			Point point = new Point(0, 0);
			for (int loop = 0; loop < 100; ++loop) {
				point.x = random.nextInt(maxX - minX) + minX;
				point.y = random.nextInt(maxY - minY) + minY;
				if (polygon.contains(point)) {
					break;
				}
			}

			polygon.toString();
		}

		String answer = joke(problem.problemId);
		if (answer != null) {
			return answer;
		}

		final Point point = new Point(random.nextInt(Constant.CLICK_IMAGE_WIDTH), random.nextInt(Constant.CLICK_IMAGE_HEIGHT));
		return point.toString();
	}

	private String getAnswerTegaki(PacketProblemData problem) {
		if (correct()) {
			return problem.answer[0];
		}

		String answer = joke(problem.problemId);
		if (answer != null) {
			return answer;
		}

		final char[] array = problem.answer[0].toCharArray();
		for (int i = 0; i < array.length; ++i) {
			array[i] += random.nextInt(3) - 1;
		}
		return new String(array);
	}

	public String getGreeting() {
		return GREETING[random.nextInt(GREETING.length)];
	}
}
